package com.browsesoft.tools;

import java.util.Calendar;
import java.util.GregorianCalendar;

import com.browsesoft.PropertiesService;

/**
 * 日期类，对jdk的日期类进行了包装，提供了更方便的使用方式
 */
public class BSCalendar {
	/**
	 * jdk中的日期表示
	 */
	private Calendar calendar = null;

	/**
	 * 使用固定格式的字符串构造，字符串格式为yyyymmdd
	 */
	public BSCalendar(String format) {
		format = format.replaceAll("-", "");
		// 从字符串中取得年，月，日
		int year = Integer.parseInt(format.substring(0, 4));
		int month = Integer.parseInt(format.substring(4, 6)) - 1;
		// 如果没有天，默认为1
		int day = 1;
		try {
			day = Integer.parseInt(format.substring(6, 8));
		} catch (Exception e) {
		}
		this.calendar = new GregorianCalendar(year, month, day);
	}

	/**
	 * 消除多余字符
	 */
	private String clear(String format) {
		// 消除多余字符
		if (format.indexOf("-") != -1) {
			format = format.replaceAll("-", "");
		}
		if (format.indexOf(" ") != -1) {
			format = format.replaceAll(" ", "");
		}
		if (format.indexOf(":") != -1) {
			format = format.replaceAll(":", "");
		}
		return format;
	}

	/**
	 * 使用固定格式的字符串构造，字符串格式为yyyymmddhhttss或者yyyymmdd
	 */
	public BSCalendar(String time, String format) {
		// 消除多余字符
		time = this.clear(time);
		format = this.clear(format);
		
		// 取年
		int index = format.indexOf("yyyy");
		int year = 0;
		if(index != -1) {
			year = Integer.parseInt(time.substring(index, index+4));
		}
		// 取月
		index = format.indexOf("mm");
		int month = 0;
		if(index != -1) {
			month = Integer.parseInt(time.substring(index, index+2));
		}
		// 取日
		index = format.indexOf("dd");
		int dd = 0;
		if(index != -1) {
			dd = Integer.parseInt(time.substring(index, index+2));
		}
		// 取小时
		index = format.indexOf("hh");
		int hour = 0;
		if(index != -1) {
			hour = Integer.parseInt(time.substring(index, index+2));
		}
		// 取分
		index = format.indexOf("tt");
		int minutes = 0;
		if(index != -1) {
			minutes = Integer.parseInt(time.substring(index, index+2));
		}
		// 秒
		index = format.indexOf("ss");
		int second = 0;
		if(index != -1) {
			second = Integer.parseInt(time.substring(index, index+2));
		}
		this.calendar = new GregorianCalendar(year, month, dd, hour,
					minutes, second);
	}

	/**
	 * 复制方法
	 */
	public Object clone() {
		// 构造空日期
		BSCalendar result = new BSCalendar();
		// 给日期设置jdk日期
		result.calendar = (Calendar) this.calendar.clone();
		return result;
	}

	/**
	 * 空构造
	 */
	private BSCalendar() {
	}

	/**
	 * 得到系统当前日期
	 */
	public static BSCalendar now() {
		// 得到系统当前时间
		return new BSCalendar(GregorianCalendar.getInstance());
	}

	/**
	 * 得到系统当前年月
	 */
	public static BSCalendar nowMonth() {
		String nowmonth = new BSCalendar(GregorianCalendar.getInstance())
				.toString().substring(0, 6);
		return new BSCalendar(nowmonth);
	}

	/**
	 * 得到统计意义上当前月的开始天，一般是上月底的某一天，具体天在属性文件里指明，如果没有指明，从26日开始
	 */
	public static BSCalendar startDayOfMonth() {
		// 得到单值
		String str = PropertiesService.getProperty("Month", "startDay", "26");
		int day = Integer.parseInt(str);
		// 产生本月开始天
		BSCalendar c = BSCalendar.now();
		c = c.getCalendarAfterMonth(-1);
		c.setDay(day);
		return c;
	}

	/**
	 * 得到统计意义上当前月的结束天
	 */
	public static BSCalendar endDayOfMonth() {
		// 产生本月结束天
		BSCalendar c = BSCalendar.startDayOfMonth();
		c = c.getCalendarAfterMonth(1);
		c = c.getCalendarAfterDay(-1);
		return c;
	}

	/**
	 * 使用jdk中给定的日期构造
	 */
	private BSCalendar(Calendar calendar) {
		this.calendar = calendar;
		// 由于有些机器的小时会莫名其妙的少,所以设置调整值
		//String v = PropertiesService.getProperty("date", "hour", "0");
		String v ="0";
		int i = Integer.parseInt(v);
		this.calendar.add(Calendar.HOUR_OF_DAY, i);
	}

	/**
	 * 得到年
	 * 
	 * @return 年
	 */
	public int getYear() {
		return this.calendar.get(Calendar.YEAR);
	}

	/**
	 * 把当前年更新到指定年
	 */
	public void setYear(int year) {
		this.calendar.set(year, this.getMonth() - 1, this.getDay());
	}

	/**
	 * 把当前月份更新到指定月份
	 */
	public void setMonth(int month) {
		this.calendar.set(this.getYear(), month - 1, this.getDay());
	}

	/**
	 * 把当前天更新到指定天
	 */
	public void setDay(int day) {
		this.calendar.set(this.getYear(), this.getMonth() - 1, day);
	}

	/**
	 * 得到天
	 * 
	 * @return 天
	 */
	public int getDay() {
		return this.calendar.get(Calendar.DATE);
	}

	/**
	 * 得到小时
	 * 
	 * @return 小时 一天以24小时计算
	 */
	public int getHour() {
		return this.calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * 更新小时 一天以24小时计算
	 */
	public void setHour(int hour) {
		this.calendar.set(this.getYear(), this.getMonth() - 1, this.getDay(),
				hour, this.getMinute());
	}

	/**
	 * 得到分钟
	 * 
	 * @return 分钟
	 */
	public int getMinute() {
		return this.calendar.get(Calendar.MINUTE);
	}

	/**
	 * 得到秒
	 */
	public int getSceond() {
		return this.calendar.get(Calendar.SECOND);
	}

	/**
	 * 更新分钟
	 */
	public void setMinute(int minute) {
		this.calendar.set(this.getYear(), this.getMonth() - 1, this.getDay(),
				this.getHour(), minute);
	}

	/**
	 * 得到当天是星期几
	 * 
	 * @return 星期几
	 */
	public int getDayOfWeek() {
		int ret = this.calendar.get(Calendar.DAY_OF_WEEK);
		return ret;
	}

	/**
	 * 得到月份
	 * 
	 * @return 月份
	 */
	public int getMonth() {
		return this.calendar.get(Calendar.MONTH) + 1;
	}

	/**
	 * 计算两个日期之间相差几个月
	 * 
	 * @param other
	 *            要计算的其他日期
	 * @return 相差几个月
	 */
	public int getMonthDispersion(BSCalendar other) {
		// 把两个日期换算成绝对月份
		int month1 = this.getYear() * 12 + this.getMonth();
		int month2 = other.getYear() * 12 + other.getMonth();
		// 返回绝对月份的差值
		return month1 - month2;
	}

	/**
	 * 计算两个日期之间相差几年
	 * 
	 * @param other
	 *            要计算的其他日期
	 * @return 相差几年
	 */
	public int getYearDispersion(BSCalendar other) {
		// 返回两个日期对应的年的差值
		return this.getYear() - other.getYear();
	}

	/**
	 * 计算两个日期之间相差几天
	 */
	public int getDayDispersion(BSCalendar other) {
		// 得到两个日期所对应的绝对天
		long time1 = this.getTime();
		int day1 = (int) (time1 / (24 * 60 * 60 * 1000));
		long time2 = other.getTime();
		int day2 = (int) (time2 / (24 * 60 * 60 * 1000));
		// 返回天所对应的绝对值
		return day1 - day2;
	}

	/**
	 * 计算两个日期相差小时数
	 */
	public int getHourDispersion(BSCalendar other) {
		long time1 = this.getTime();
		long time2 = other.getTime();
		int hour = (int) ((time1 - time2) / (60 * 60 * 1000));
		return hour;
	}

	/**
	 * 得到以毫秒计算的时间
	 * 
	 * @return 以毫秒计算的时间
	 */
	public long getTime() {
		return this.calendar.getTimeInMillis();
	}

	/**
	 * 得到相对当前日期前后几天的新日期
	 */
	public BSCalendar getCalendarAfterDay(int day) {
		// 复制当前日期
		BSCalendar result = (BSCalendar) this.clone();
		// 结果前后移动几天
		result.calendar.add(Calendar.DATE, day);
		return result;
	}

	/**
	 * 得到相对当前日期前后几月的新日期
	 */
	public BSCalendar getCalendarAfterMonth(int month) {
		// 复制当前日期
		BSCalendar result = (BSCalendar) this.clone();
		// 结果前后移动几月
		result.calendar.add(Calendar.MONTH, month);
		return result;
	}

	/**
	 * 得到相对当前日期前后几年的新日期
	 */
	public BSCalendar getCalendarAfterYear(int year) {
		// 复制当前日期
		BSCalendar result = (BSCalendar) this.clone();
		// 结果前后移动几年
		result.calendar.add(Calendar.YEAR, year);
		return result;
	}

	/**
	 * 转换成固定格式的字符串，字符串格式为yyyy-mm-dd
	 */
	public String toString() {
		// 得到年月日
		int year = this.calendar.get(Calendar.YEAR);
		int month = this.calendar.get(Calendar.MONTH) + 1;
		int day = this.calendar.get(Calendar.DAY_OF_MONTH);
		// 转换成串
		String strMonth = Integer.toString(month + 100);
		String strDay = Integer.toString(day + 100);
		String result = Integer.toString(year) + strMonth.substring(1)
				+ strDay.substring(1);
		return result;
	}

	/**
	 * 转换成不同格式的字符串，字符串格式为format
	 * 其中"年"用"yyyy(YYYY)"表示;"月"用"mm(MM)"表示;"日"用"dd(DD)";
	 * "小时"用"hh(HH)"表示；“分钟”用"tt(TT)"表示；“秒钟”用"ss(SS)"表示 用yy代替yyyy表示年份用两位数表示；
	 * 用m代替mm表示小月（0-9）前面不用添零； 用d代替dd表示小日（0-9）前不用添零
	 * "中文星期"用"cw(CW)"表示;"英文星期"用"ew(EW)"表示 不带格式时的默认格式为 "yyyymmdd" 显示如:"20050202"
	 * 格式举例1："yyyy年mm月dd日"； 显示如： "2005年02月02日" 格式举例2："yyyy年mm月dd日 cw"
	 * 显示如："2005年02月02日 星期三" 格式举例3: " yyyy-mm-dd ew" 显示如:"2005-02-02 Wednesday"
	 * 格式举例4: "yymmdd" 显示如:"050202 "
	 */
	public String toString(String format) {
		String result = null;
		format = format.toUpperCase();
		// 得到年月日
		int year = this.calendar.get(Calendar.YEAR);
		int month = this.calendar.get(Calendar.MONTH) + 1;
		int day = this.calendar.get(Calendar.DAY_OF_MONTH);
		int weekday = this.calendar.get(Calendar.DAY_OF_WEEK) - 1;
		// 得到小时、分钟、秒
		int hour = this.getHour();
		int minute = this.getMinute();
		int second = this.getSceond();
		// 转换成串
		// 替换格式中的年
		format = getYearInFormat(format, year);
		// 替换格式中的月
		format = getMonthInFormat(format, month);
		// 替换格式中的日
		format = getDayInFormat(format, day);
		// 替换格式中的小时
		format = getHourInFormat(format, hour);
		// 替换格式中的分钟
		format = getMinuteInFormat(format, minute);
		// 替换格式中的秒
		format = getSecondInFormat(format, second);
		// 替换格式中的星期几
		result = getWeekDayInFormat(format, weekday);
		return result;
	}

	/**
	 * 获得中文的星期几
	 * 
	 * @param myweekday
	 *            :Calendar.DAY_OF_WEEK的返回值
	 * @return 中文的星期几
	 */
	public String getChinaDayOfWeek(int myweekday) {
		String weekday = null;
		if (myweekday == 0) {
			weekday = " 星期日 ";
		} else if (myweekday == 1) {
			weekday = " 星期一 ";
		} else if (myweekday == 2) {
			weekday = " 星期二 ";
		} else if (myweekday == 3) {
			weekday = " 星期三 ";
		} else if (myweekday == 4) {
			weekday = " 星期四 ";
		} else if (myweekday == 5) {
			weekday = " 星期五 ";
		} else if (myweekday == 6) {
			weekday = " 星期六 ";
		}
		return weekday;
	}

	/**
	 * 获得中文的星期几
	 * 
	 * @param myweekday
	 *            :Calendar.DAY_OF_WEEK的返回值
	 * @return 中文的星期几
	 */
	public String getChinaNumberOfWeek(int myweekday) {
		String weekday = null;
		if (myweekday == 0) {
			weekday = " 日 ";
		} else if (myweekday == 1) {
			weekday = "一";
		} else if (myweekday == 2) {
			weekday = "二";
		} else if (myweekday == 3) {
			weekday = "三";
		} else if (myweekday == 4) {
			weekday = "四";
		} else if (myweekday == 5) {
			weekday = "五";
		} else if (myweekday == 6) {
			weekday = "六";
		}
		return weekday;
	}

	/**
	 * 获得英文的星期几
	 * 
	 * @param myweekday
	 *            :Calendar.DAY_OF_WEEK的返回值
	 * @return 英文的星期几
	 */
	public String getEnglishDayOfWeek(int myweekday) {
		String weekday = null;
		if (myweekday == 0) {
			weekday = " Sunday ";
		} else if (myweekday == 1) {
			weekday = " Monday ";
		} else if (myweekday == 2) {
			weekday = " Tuesday ";
		} else if (myweekday == 3) {
			weekday = " Wednesday ";
		} else if (myweekday == 4) {
			weekday = " Thursday ";
		} else if (myweekday == 5) {
			weekday = " Friday ";
		} else if (myweekday == 6) {
			weekday = " Saturday ";
		}
		return weekday;
	}

	/**
	 * 替代格式中的年
	 * 
	 * @param format
	 *            ：显示格式
	 * @param year：年
	 * @return 替换年以后的格式
	 */
	private String getYearInFormat(String format, int year) {
		String result = null;
		// 替换四位数表示的年份
		String longyear = Integer.toString(year);
		format = format.replaceAll("YYYY", longyear);
		// 替换两位数表示的年份
		String shortyear = longyear.substring(2);
		result = format.replaceAll("YY", shortyear);
		return result;
	}

	/**
	 * 替代格式中的月
	 * 
	 * @param format
	 *            ：显示格式
	 * @param month：月
	 * @return 替换月以后的格式
	 */
	private String getMonthInFormat(String format, int month) {
		String result = null;
		// 得到月份的两位表示表达式
		String longMonth = Integer.toString(100 + month);
		longMonth = longMonth.substring(1);
		// 替换两位表示的月份
		format = format.replaceAll("MM", longMonth);
		// 替换用一位表示的月份
		result = format.replaceAll("M", Integer.toString(month));
		return result;
	}

	/**
	 * 替代格式中的日
	 * 
	 * @param format
	 *            ：显示格式
	 * @param day：日
	 * @return 替换日以后的格式
	 */
	private String getDayInFormat(String format, int day) {
		String result = null;
		// 得到月份的两位表示表达式
		String longday = Integer.toString(100 + day);
		longday = longday.substring(1);
		// 替换两位表示的日期
		format = format.replaceAll("DD", longday);
		// 替换用一位表示的日期
		result = format.replaceAll("D", Integer.toString(day));
		return result;
	}

	/**
	 * 替代格式中的星期
	 * 
	 * @param format
	 *            ：显示格式
	 * @param weekday：Day_Of_Week的返回值
	 * @return 替换星期以后的格式
	 */
	private String getWeekDayInFormat(String format, int weekday) {
		String result = null;
		// 替换中文星期几
		format = format.replaceAll("CW", this.getChinaDayOfWeek(weekday));
		// 替换英文星期几
		result = format.replaceAll("EW", this.getEnglishDayOfWeek(weekday));
		return result;
	}

	/**
	 * 替代格式中的小时
	 * 
	 * @param format
	 *            ：显示格式
	 * @param hour：hour的返回值
	 * @return 替换小时以后的格式
	 */
	private String getHourInFormat(String format, int hour) {
		String result = null;
		// 得到月份的两位表示表达式
		String longday = Integer.toString(100 + hour);
		longday = longday.substring(1);
		// 替换两位表示的日期
		format = format.replaceAll("HH", longday);
		// 替换用一位表示的日期
		result = format.replaceAll("H", Integer.toString(hour));
		return result;
	}

	/**
	 * 替代格式中的分钟
	 * 
	 * @param format
	 *            ：显示格式
	 * @param minute：minute的返回值
	 * @return 替换分钟以后的格式
	 */
	private String getMinuteInFormat(String format, int minute) {
		String result = null;
		// 得到月份的两位表示表达式
		String longday = Integer.toString(100 + minute);
		longday = longday.substring(1);
		// 替换两位表示的日期
		format = format.replaceAll("TT", longday);
		// 替换用一位表示的日期
		result = format.replaceAll("T", Integer.toString(minute));
		return result;
	}

	/**
	 * 替换格式中的秒
	 */
	private String getSecondInFormat(String format, int second) {
		String result = "";
		// 得到月份的两位表示表达式
		String longday = Integer.toString(100 + second);
		longday = longday.substring(1);
		// 替换两位表示的日期
		format = format.replaceAll("SS", longday);
		// 替换用一位表示的日期
		result = format.replaceAll("S", Integer.toString(second));
		return result;
	}

	/**
	 * 得到当前周是本年的第几周
	 * 
	 * @return
	 */
	public int getWeekOfYear() {
		return this.calendar.get(Calendar.WEEK_OF_YEAR);
	}

	/**
	 * 得到当前周是本月的第几周
	 */
	public int getWeekOfMonth() {
		return this.calendar.get(Calendar.WEEK_OF_MONTH);
	}

	/**
	 * 得到两个日期之间相差的分钟 返回两个日期相差的分钟数,返回为正值
	 */
	public static int getDisparityForMinutes(BSCalendar bs1, BSCalendar bs2) {
		int result = 0;
		// 取得bs1的毫秒数
		long one = bs1.getTime();
		// 取得bs2的毫秒数
		long other = bs2.getTime();
		if (one < other) {
			result = Integer.parseInt(Long.toString(other - one)) / 1000;
		} else if (one > other) {
			result = Integer.parseInt(Long.toString(other - one)) / 1000;
		} else {
			result = 0;
		}
		return result;
	}

	/**
	 * 返回本月的头一天
	 */
	public BSCalendar getFirstDayOfMonth() {
		// 得到当前的日期
		int day = this.getDay();
		// 往前推day-1天
		return this.getCalendarAfterDay(-(day - 1));
	}

	/**
	 * 返回本月的最后一天
	 */
	public BSCalendar getEndDayOfMonth() {
		// 得到当前日期
		int day = this.getDay();
		// 往后推
		return this.getCalendarAfterDay(this.getDaysOfMonth() - day);
	}

	/**
	 * 得到今天是星期几，从星期一算
	 * 
	 * @param first
	 *            本周从星期几算
	 */
	public int getDayOfWeek(int first) {
		// 得到星期几
		int day = this.calendar.get(Calendar.DAY_OF_WEEK);
		// 如果在后面
		if (day > first) {
			// 返回减的结果
			return day - first;
		}
		// 返回循环减的结果
		return 7 - (first - day);
	}

	/**
	 * 得到本月头一周有几天空缺
	 */
	public int getNullDaysOfFirstWeek() {
		// 得到第一天是星期几，从星期1算
		int dayOfWeek = this.getFirstDayOfMonth().getDayOfWeek(1);
		return dayOfWeek - 1;
	}

	/**
	 * 得到本月天数
	 */
	public int getDaysOfMonth() {
		return this.calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 得到当前周第一天的年月日yyyymmdd
	 */
	public BSCalendar getFirstDayOfWeek() {
		// 得到当前是星期几
		int day_of_week = this.calendar.get(Calendar.DAY_OF_WEEK);
		return new BSCalendar(this.getCalendarAfterDay(2 - day_of_week)
				.toString());
	}

	/**
	 * 得到当前周最后一天的年月日yyyymmdd
	 */
	public BSCalendar getEndDayOfWeek() {
		// 得到当前是星期几
		int day_of_week = this.calendar.get(Calendar.DAY_OF_WEEK);
		return new BSCalendar(this.getCalendarAfterDay(8 - day_of_week)
				.toString());
	}

	/**
	 * 得到前后几周的第一天的年月日yyyymmdd
	 */
	public BSCalendar getFirstDayOfAfterWeek(int weeks) {
		BSCalendar now = now().getCalendarAfterDay(weeks * 7);
		return now.getFirstDayOfWeek();
	}

	/**
	 * 把数据库里的时间形式yyyy-mm-dd hh:tt:ss 转换为yyyymmdd形式
	 */
	public static String transform(String str) {
		str = str.substring(0, 10);
		str = str.replaceAll("-", "");
		return str;
	}

	/**
	 * 设置一个星期的第一天实星期几 美国是SUNDAY 中国,法国是MONDAY 0为星期天,1为星期一
	 */
	public void setFirstDayOfWeek(int i) {
		// 如果
		if (i == 0) {
			// 设置星期天为第一天
			this.calendar.setFirstDayOfWeek(Calendar.SUNDAY);
		} else if (i == 1) {
			// 设置星期一为第一天
			this.calendar.setFirstDayOfWeek(Calendar.MONDAY);
		}
	}
}
